﻿using AutoMapper;
using ManagementApi.Models;
using ManagementApi.Models.Account;
using ManagementApi.Models.Corp;
using ManagementApi.Models.Manage;
using ManagementApi.Models.Person;
using ManagementApi.Models.Project;
using ManagementApi.Models.System.User;
using ManagementApi.Services;
using ManagementApi.TreeParty.SMS;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Modules;
using Modules.Commander;
using Modules.Constructor;
using Modules.Corp;
using Modules.Manager;
using Modules.Person;
using Modules.Project;
using Modules.SMS;
using Modules.SMS.Entitys;
using Modules.System.Security;
using Modules.System.Settings;
using Modules.System.Settings.Entitys;
using Modules.System.User;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Caching.Redis;
using PmSoft.Entity;
using PmSoft.Exceptions;
using PmSoft.Utilities;
using System.ComponentModel.DataAnnotations;
using static Modules.Project.ProjectConstants;

namespace ManagementApi.Controllers
{
    /// <summary>
    /// 账号注册、密码找回、注册短信相关业务接口
    /// </summary>
    [Route("/api/v1/account")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private readonly UserService userSevice;
        private readonly CorpService corpService;
        private readonly ConstructorService constructorService;
        private readonly ManagerService managerService;
        private readonly SmsSendLogService smsSendLogService;
        private readonly ProjectService projectService;
        private readonly IMemoryCache memoryCache;
        private readonly ISMSService sMSService;
        private readonly IMapper mapper;
        private readonly PublicPersonService publicPersonService;
        private readonly PersonService personService;
        private readonly PmSoftRedisCache redisCache;
        private readonly CommanderService commanderService;
        private readonly SecurityService securityService;
        private readonly CardReaderService cardReaderService;
        private readonly IApplicationContext applicationContext;

        /// <summary>
        /// 构造函数
        /// </summary>
        public AccountController(UserService userSevice,
            CorpService corpService,
            ConstructorService constructorService,
            ManagerService managerService,
            SmsSendLogService smsSendLogService,
            ProjectService projectService,
            ISMSService sMSService,
            IMapper mapper,
            IMemoryCache memoryCache,
            PublicPersonService publicPersonService,
            PersonService personService,
            PmSoftRedisCache redisCache,
            CommanderService commanderService,
            SecurityService securityService,
             CardReaderService cardReaderService,
             IApplicationContext applicationContext
            )
        {
            this.userSevice = userSevice;
            this.corpService = corpService;
            this.constructorService = constructorService;
            this.managerService = managerService;
            this.smsSendLogService = smsSendLogService;
            this.projectService = projectService;
            this.mapper = mapper;
            this.sMSService = sMSService;
            this.memoryCache = memoryCache;
            this.publicPersonService = publicPersonService;
            this.personService = personService;
            this.redisCache = redisCache;
            this.commanderService = commanderService;
            this.securityService = securityService;
            this.cardReaderService = cardReaderService;
            this.applicationContext = applicationContext;
        }

        /// <summary>
        /// 企业注册
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        [HttpPost("corp_reg")]
        public ApiResult CorpReg(CorpCreateForm form)
        {
            if (string.IsNullOrEmpty(form.VerificationCode))
                return ApiResult.Failure("短信验证码不能为空");

            if (!smsSendLogService.Validate(form.LinkTel, form.VerificationCode, MsgType.VerificationCode))
                return ApiResult.Failure("短信验证码错误或已过期");

            CorpInfo corpInfo = new();
            mapper.Map(form, corpInfo);
            corpInfo.HasAuth = true;
            corpService.CreateCorpInfo(corpInfo, form.Password, form.Attachments);

            return ApiResult.Success("创建成功");
        }

        /// <summary>
        /// 企业是否已存在
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        [HttpGet("corp_exists")]
        public ApiResult CorpExists([Required(ErrorMessage = "信用代码不能为空")] string code)
        {
            if (corpService.CodeExists(code))
                return ApiResult.Failure("企业信用代码已存在");
            return ApiResult.Success("企业信用代码不存在");
        }

        /// <summary>
        /// 查询企业审核结果
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        [HttpGet("corp_reg_result/{id}")]
        public ApiResult<CorpInfoDto> GetCorpInfo(string id)
        {
            var corpInfo = corpService.GetCorpInfo(id) ?? throw new BusinessException("未查询到相关企业信息");
            return ApiResult<CorpInfoDto>.Success(corpInfo.AsDetailDto(applicationContext));
        }

        /// <summary>
        /// 建设单位注册
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        [HttpPost("constructor_reg")]
        public ApiResult ConstructorReg(ConstructorCreateForm form)
        {
            constructorService.CreateConstructor(form.AsConstructor(), form.Password);

            return ApiResult.Success("创建成功");
        }

        /// <summary>
        /// 建设单位是否已存在
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        [HttpGet("constructor_exists")]
        public ApiResult ConstructorExists([Required(ErrorMessage = "信用代码不能为空")] string code)
        {
            if (constructorService.CodeExists(code))
                return ApiResult.Failure("建设单位已存在");
            return ApiResult.Success("建设单位不存在");
        }

        /// <summary>
        /// 项目管理员是否存在
        /// </summary>
        /// <param name="cardNo"></param>
        /// <returns></returns>
        [HttpGet("manager_exists")]
        public ApiResult<bool> ManagerExists([Required(ErrorMessage = "身份证号码不能为空")] string cardNo)
        {
            return ApiResult<bool>.Success(managerService.CardNoExists(cardNo));
        }

        /// <summary>
        /// 项目管理员注册 author:hzj update:2023/11/14 describe:为该方法添加绑定项目逻辑
        /// </summary>
        /// <param name="projectCheckInForm"></param>
        /// <param name="manageCreateForm"></param>
        /// <returns></returns>
        [HttpPost("manager_register")]
        public ApiResult CreateManager([FromQuery] ManageCreateForm manageCreateForm, ProjectRegisterForm projectCheckInForm)
        {
            var readerPerson = cardReaderService.GetCardInfo(manageCreateForm.Token);
            if (readerPerson == null)
                return ApiResult.Failure("请重新读取身份证");
            PersonCreateForm personCreate = new PersonCreateForm();
            personCreate.Mobile = manageCreateForm.Mobile;
            personCreate.token = manageCreateForm.Token;
            int personId = publicPersonService.SavePersonReadCard(personCreate);
            PersonInfo? personInfo = personService.GetPerson(personId);
            if (personInfo == null)
                return ApiResult.Failure("人员信息不存在");

            if (!smsSendLogService.Validate(manageCreateForm.Mobile, manageCreateForm.VerificationCode, MsgType.VerificationCode))
                return ApiResult.Failure("短信验证码错误或已过期");

            if (projectCheckInForm.LumpContractorCorpId == projectCheckInForm.SupervisorCorpId)
                return ApiResult.Failure("总包企业和监理企业不能相同");
            ManagerInfo managerInfo = new ManagerInfo();
            mapper.Map(manageCreateForm, managerInfo);
            ProjectInfo projectInfo = new ProjectInfo();
            projectInfo.CreateManagerId = managerInfo.ManagerId;
            mapper.Map(projectCheckInForm, projectInfo);
            projectInfo.CreateTime = DateTime.Now;
            projectInfo.AuditStatus = 项目审核状态.待审核;
            projectInfo.PrjStatus = 项目状态.在建;
            projectInfo.IsRegister = true;
            projectInfo.DataSource = 项目数据来源.项目注册;
            projectInfo.NeedCompletData = false;
            //若存在项目Id，则只需要绑定管理员与该项目的关联信息，以及更新项目的基础信息----hzj 2023/11/14
            if (projectCheckInForm.ProjectId > 0)
            {
                managerService.UpdateManageProjectInfo(managerInfo, projectInfo, manageCreateForm.Password, projectCheckInForm.LumpContractorCorpAmount, projectCheckInForm.SupervisorCorpAmount, projectCheckInForm.LumpContractorCorpStartDate, projectCheckInForm.LumpContractorCorpEndDate, projectCheckInForm.SupervisorCorpStartDate, projectCheckInForm.SupervisorCorpEndDate, projectCheckInForm.HasSupervisor, projectCheckInForm.Attachments, projectCheckInForm.PositionAttachments, projectCheckInForm.NoSupervisorAttachments, projectCheckInForm.EarnestAttachments, personInfo, projectCheckInForm.CommanderId, projectCheckInForm.SupervisorCorpName, projectCheckInForm.SupervisorCorpCode);
                return ApiResult.Success("创建成功");
            }
            //若不存在项目Id，则走项目的登记的原逻辑----hzj 2023/11/14
            managerService.CreateManage(managerInfo, projectInfo, manageCreateForm.Password, projectCheckInForm.LumpContractorCorpAmount, projectCheckInForm.SupervisorCorpAmount, projectCheckInForm.LumpContractorCorpStartDate, projectCheckInForm.LumpContractorCorpEndDate, projectCheckInForm.SupervisorCorpStartDate, projectCheckInForm.SupervisorCorpEndDate, projectCheckInForm.HasSupervisor, projectCheckInForm.Attachments, projectCheckInForm.PositionAttachments, projectCheckInForm.NoSupervisorAttachments, projectCheckInForm.EarnestAttachments, personInfo, projectCheckInForm.CommanderId, projectCheckInForm.SupervisorCorpName, projectCheckInForm.SupervisorCorpCode);
            return ApiResult.Success("创建成功");
        }

        /// <summary>
        /// author:hzj date:2023/11/14 describe:获取项目注册信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("register_form/{id}")]
        public ApiResult<ProjectRegisterForm> GetProjectRegisterForm(int id)
        {
            var data = projectService.GetProjectInfo(id);
            if (data == null)
                return ApiResult<ProjectRegisterForm>.Failure("项目数据不存在");
            return ApiResult<ProjectRegisterForm>.Success(data.AsForm(applicationContext));
        }

        /// <summary>
        /// 获取短信验证码
        /// </summary>
        /// <param name="phone"></param>
        /// <returns></returns>
        [HttpGet("verificationcode")]
        public ApiResult GetSMSVerificationCode(string phone)
        {
            if (string.IsNullOrWhiteSpace(phone))
                return ApiResult.Failure("电话号码不能为空");

            string code = SmsBuidler.Instance().GetValidateCode();
            SmsModel smsModel = SmsBuidler.Instance().ValidateCode(code);
            smsModel.Code = code;
            //发送验证码
            smsSendLogService.Send(phone, smsModel);
            return ApiResult.Success("验证码发送成功");
        }

        #region 找回密码

        /// <summary>
        /// 通过用户类型及账号换取token
        /// </summary>
        /// <param name="userType"></param>
        /// <param name="loginName"></param>
        /// <param name="verifyCode"></param>
        /// <returns></returns>
        [HttpGet("GetRetrievePasswordToken/{userType}")]
        public ApiResult<string> GetRetrievePasswordToken(UserType userType, [Required(ErrorMessage = "token信息不能为空")] string loginName, string verifyCode)
        {
            if (string.IsNullOrEmpty(verifyCode))
                return ApiResult<string>.Failure("短信验证码不能为空");
            string phone = string.Empty;
            switch (userType)
            {
                case UserType.SysUser:
                    phone = userSevice.GetUser(loginName)?.Mobile ?? string.Empty; break;
                case UserType.Constructor:
                    phone = constructorService.GetConstructorInfo(loginName)?.LegalMobile ?? string.Empty; break;
                case UserType.Corp:
                    phone = corpService.GetCorpInfo(loginName)?.LinkTel ?? string.Empty; break;
                case UserType.Manager:
                    phone = managerService.GetManagerInfo(loginName)?.Mobile ?? string.Empty; break;
                case UserType.Commander:
                    phone = commanderService.GetCommanderInfo(loginName)?.Mobile ?? string.Empty; break;
                default:
                    break;
            }

            if (!smsSendLogService.Validate(phone, verifyCode, MsgType.VerificationCode))
                return ApiResult<string>.Failure("短信验证码错误或已过期");

            string token = Guid.NewGuid().ToString().Replace("-", "");
            RetrievePasswordTokenForm form = new() { UserType = userType, LoginName = loginName, ExpirationTime = DateTime.Now.AddMinutes(5) };
            switch (userType)
            {
                case UserType.SysUser:
                    SysUser? sysUser = userSevice.GetUser(loginName);
                    if (sysUser != null) form.Phone = sysUser.Mobile;
                    break;

                case UserType.Constructor:
                    ConstructorInfo? constructorInfo = constructorService.GetConstructorInfo(loginName);
                    if (constructorInfo != null) form.Phone = constructorInfo.LegalMobile;
                    break;

                case UserType.Commander:
                    CommanderInfo? commanderInfo = commanderService.GetCommanderInfo(loginName);
                    if (commanderInfo != null) form.Phone = commanderInfo.Mobile;
                    break;

                case UserType.Corp:
                    CorpInfo? corpInfo = corpService.GetCorpInfo(loginName);
                    if (corpInfo != null) form.Phone = corpInfo.LinkTel;
                    break;

                case UserType.Manager:
                    ManagerInfo? managerInfo = managerService.GetManagerInfo(loginName);
                    if (managerInfo != null) form.Phone = managerInfo.Mobile;
                    break;

                default:
                    break;
            }
            redisCache.Add(token, form, TimeSpan.FromMinutes(5));
            return ApiResult<string>.Success(token);
        }

        /// <summary>
        /// 查询短信发送状态
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet("getSMSSendStatus/{token}")]
        public ApiResult GetSMSSendStatus([Required(ErrorMessage = "token信息不能为空")] string token)
        {
            RetrievePasswordTokenForm? form = redisCache.Get<RetrievePasswordTokenForm>(token);
            if (form == null)
                return ApiResult.Failure("token信息不存在");
            if (form.ExpirationTime < DateTime.Now)
                return ApiResult.Failure("token信息过期");
            var smsLogs = smsSendLogService.GetSendLogs(form.Phone, new SMSSendQuery { Type = MsgType.RetrievePassword, EndDate = DateTime.Now.AddMinutes(-10) });
            if (smsLogs == null || !smsLogs.Any())
                return ApiResult.Failure($"没有查询到{form.Phone.AsEncryptedPhone()}的短信发送记录");
            SmsSendLog? smsSendLog = smsLogs.OrderByDescending(x => x.CreateTime).FirstOrDefault();
            if (smsSendLog?.CreateTime < DateTime.Now.AddMinutes(-5))
                return ApiResult.Failure($"短信有效期为5分钟，请重新发送");

            #region 查询短信发送规则

            RetrievePasswordSetting passwordSetting = SettingManager<RetrievePasswordSetting>.Instance.Get();
            switch (form.UserType)
            {
                case UserType.SysUser:
                    if (passwordSetting.SysUserContent != smsSendLog?.MsgContent)
                        return ApiResult.Failure($"发送内容无效，应为 {passwordSetting.SysUserContent}");
                    break;

                case UserType.Constructor:
                    if (passwordSetting.ConstructorContent != smsSendLog?.MsgContent)
                        return ApiResult.Failure($"发送内容无效，应为 {passwordSetting.ConstructorContent}");
                    break;

                case UserType.Commander:
                    if (passwordSetting.CommanderContent != smsSendLog?.MsgContent)
                        return ApiResult.Failure($"发送内容无效，应为{passwordSetting.CommanderContent}");
                    break;

                case UserType.Corp:
                    if (passwordSetting.CorpContent != smsSendLog?.MsgContent)
                        return ApiResult.Failure($"发送内容无效，应为 {passwordSetting.CorpContent}");
                    break;

                case UserType.Manager:
                    if (passwordSetting.ManagerContent != smsSendLog?.MsgContent)
                        return ApiResult.Failure($"发送内容无效，应为 {passwordSetting.ManagerContent}");
                    break;

                default:
                    break;
            }

            #endregion 查询短信发送规则

            return ApiResult.Success("短信校验通过");
        }

        /// <summary>
        /// 找回密码提交
        /// </summary>
        /// <param name="token"></param>
        /// <param name="passWord"></param>
        /// <returns></returns>
        [HttpPut("submitRetrievePassword/{token}")]
        public ApiResult SubmitRetrievePassword([Required(ErrorMessage = "token信息不能为空")] string token, [Required(ErrorMessage = "密码不能为空")] string passWord)
        {
            RetrievePasswordTokenForm? form = redisCache.Get<RetrievePasswordTokenForm>(token);
            if (form == null)
                return ApiResult.Failure("token信息不存在");
            if (form.ExpirationTime < DateTime.Now)
                return ApiResult.Failure("token信息过期");
            SysSecurity? sysSecurity = new();
            switch (form.UserType)
            {
                case UserType.SysUser:
                    SysUser? sysUser = userSevice.GetUser(form.LoginName);
                    if (sysUser != null)
                    {
                        sysSecurity = securityService.GetSysSecurity(sysUser.SecurityId);
                        if (sysSecurity != null)
                            sysSecurity.Password = SecurityPasswordHelper.EncodePassword(passWord, UserPasswordFormat.SM4);
                    }
                    break;

                case UserType.Constructor:
                    ConstructorInfo? constructorInfo = constructorService.GetConstructorInfo(form.LoginName);
                    if (constructorInfo != null)
                    {
                        sysSecurity = securityService.GetSysSecurity(constructorInfo.SecurityId);
                        if (sysSecurity != null)
                            sysSecurity.Password = SecurityPasswordHelper.EncodePassword(passWord, UserPasswordFormat.SM4);
                    }
                    break;

                case UserType.Commander:
                    CommanderInfo? commanderInfo = commanderService.GetCommanderInfo(form.LoginName);
                    if (commanderInfo != null)
                    {
                        sysSecurity = securityService.GetSysSecurity(commanderInfo.SecurityId);
                        if (sysSecurity != null)
                            sysSecurity.Password = SecurityPasswordHelper.EncodePassword(passWord, UserPasswordFormat.SM4);
                    }
                    break;

                case UserType.Corp:
                    CorpInfo? corpInfo = corpService.GetCorpInfo(form.LoginName);
                    if (corpInfo != null)
                    {
                        sysSecurity = securityService.GetSysSecurity(corpInfo.SecurityId);
                        if (sysSecurity != null)
                            sysSecurity.Password = SecurityPasswordHelper.EncodePassword(passWord, UserPasswordFormat.SM4);
                    }
                    break;

                case UserType.Manager:
                    ManagerInfo? managerInfo = managerService.GetManagerInfo(form.LoginName);
                    if (managerInfo != null)
                    {
                        sysSecurity = securityService.GetSysSecurity(managerInfo.SecurityId);
                        if (sysSecurity != null)
                            sysSecurity.Password = SecurityPasswordHelper.EncodePassword(passWord, UserPasswordFormat.SM4);
                    }
                    break;

                default:
                    break;
            }
            if (sysSecurity != null)
                securityService.Update(sysSecurity);
            //移除token，保证每个token只能使用一次
            redisCache.Remove(token);
            return ApiResult.Success("密码修改成功");
        }

        #endregion 找回密码
    }
}